package com.unitd.base.generator;

import com.unitd.base.frame.utils.DateUtils;
import com.unitd.base.frame.utils.StringUtils;
import freemarker.template.Template;

import java.io.*;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.util.*;

/**
 * 代码生成器
 *
 * @author Hudan
 * @version 1.0
 * @filename CodeGenerateUtils.java
 * @copyright www.unitd.com
 * @date 18-8-29
 */
public class CodeGenerateUtils {

	private final String author = "Hudan";
	private final String currDate = DateUtils.format2DateStr(new Date(), "yyyy-MM-dd");
	private final String javaFilePath = "/Volumes/Data/Project/WorkPro/unitd/ShopPro_KF/unitd-logistics/src/main/java/";
	private final String dtoFilePath = "/Volumes/Data/Project/WorkPro/unitd/ShopPro_KF/unitd-logistics/src/main/java/";
	private final String resourceFilePath = "/Volumes/Data/Project/WorkPro/unitd/ShopPro_KF/unitd-logistics/src/main/resources/";
	private final String packageName = "com.unitd.base";
	private final String tableName = "TEST";
	private final String tableDesc = "物流详细信息表";
	private final String className = "Test";
	/**
	 * 需要生成的模块名称
	 */
	private final String moduleName = "logistics";

	private String driver = "com.mysql.jdbc.Driver";
	private String url = "jdbc:mysql://database.unitd.com:3306/unitd_logistics";
	private String user = "root";
	private String password = "root";


	public static void main(String[] args) {
		CodeGenerateUtils codeGenerateUtils = new CodeGenerateUtils();
		codeGenerateUtils.generate();
	}

	/**
	 * 获取数据库连接
	 *
	 * @return 数据库连接对象
	 */
	public Connection getConnection() throws Exception {
		Class.forName(driver);
		return DriverManager.getConnection(url, user, password);
	}

	public void generate() {
		try {
			Connection connection = getConnection();
			DatabaseMetaData databaseMetaData = connection.getMetaData();
			ResultSet resultSet = databaseMetaData.getColumns(null, "%", tableName, "%");


			List<ColumnClass> columnClassList = new ArrayList<>();
			ColumnClass columnClass = null;
			while (resultSet.next()) {
				//id、create_time、update_time 字段略过
				if (resultSet.getString("COLUMN_NAME").toLowerCase().equals("id")) continue;
				if (resultSet.getString("COLUMN_NAME").toLowerCase().equals("create_time")) continue;
				if (resultSet.getString("COLUMN_NAME").toLowerCase().equals("update_time")) continue;

				columnClass = new ColumnClass();
				//获取字段名称
				columnClass.setColumnName(resultSet.getString("COLUMN_NAME"));
				//获取字段类型
				columnClass.setColumnType(resultSet.getString("TYPE_NAME"));
				//转换字段名称，如 sys_name 变成 SysName
				columnClass.setChangeColumnName(StringUtils.toCamelCase(resultSet.getString("COLUMN_NAME")));
				//字段在数据库的注释
				columnClass.setColumnComment(resultSet.getString("REMARKS"));
				columnClassList.add(columnClass);
			}
			Map<String, Object> dataMap = new HashMap<>();
			dataMap.put("model_column", columnClassList);

//			/* 生成实体Entity类 */
//			generateModelFile(resultSet, dataMap);
//			//生成Mapper文件
//			generateMapperFile(resultSet, dataMap);
//			// 生成Dao文件
//			generateDaoFile(resultSet);
			//生成服务层接口文件
			generateServiceFile();
			//生成服务实现层文件
			generateServiceImplFile();

			/* 生成实体DTO类 */
			generateDTOFile(resultSet, dataMap);
			/* 生成provider文件 */
			generateProviderFile();
			/* 生成providerImpl文件 */
			generateProviderImplFile();

			//生成Controller层文件
			generateControllerFile();
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			System.out.println("代码生成结束!");
		}
	}

	/**
	 * 生成实体类类
	 *
	 * @param resultSet 查询的数据结果集
	 * @param dataMap   需要读取到模板文件上的数据模型
	 * @throws Exception
	 */
	private void generateModelFile(ResultSet resultSet, Map<String, Object> dataMap) throws Exception {
		final String suffix = ".java";
		final String path = javaFilePath + packageName.replace(".", "/") + "/module/" + moduleName + "/model/" + className + suffix;
		final String templateName = "Model.ftl";

		File mapperFile = new File(path);
		if (!mapperFile.getParentFile().exists()) mapperFile.getParentFile().mkdirs();

		generateFileByTemplate(templateName, mapperFile, dataMap);
	}

	/**
	 * 生成DTO类
	 *
	 * @param resultSet 查询的数据结果集
	 * @param dataMap   需要读取到模板文件上的数据模型
	 * @throws Exception
	 */
	private void generateDTOFile(ResultSet resultSet, Map<String, Object> dataMap) throws Exception {
		final String suffix = "DTO.java";
		final String path = javaFilePath + packageName.replace(".", "/") + "/module/" + moduleName + "/dto/" + className + suffix;
		final String templateName = "DTO.ftl";

		File mapperFile = new File(path);
		if (!mapperFile.getParentFile().exists()) mapperFile.getParentFile().mkdirs();

		generateFileByTemplate(templateName, mapperFile, dataMap);
	}

	/**
	 * 生成Mapper类
	 *
	 * @throws Exception
	 */
	private void generateDaoFile() throws Exception {
		final String suffix = "Mapper.java";
		final String path = javaFilePath + packageName.replace(".", "/") + "/module/" + moduleName + "/mybatis/mapper/" + className + suffix;
		final String templateName = "Dao.ftl";

		generateFileByTemplate(templateName, path);
	}

	/**
	 * 生成Mappe文件
	 *
	 * @param dataMap 需要读取到模板文件上的数据模型
	 * @throws Exception
	 */
	private void generateMapperFile(Map<String, Object> dataMap) throws Exception {
		final String suffix = "Mapper.xml";
		final String path = resourceFilePath + "/mybatis/mapper/" + moduleName + className + suffix;
		final String templateName = "Mapper.ftl";

		File mapperFile = new File(path);
		if (!mapperFile.getParentFile().exists()) mapperFile.getParentFile().mkdirs();

		generateFileByTemplate(templateName, mapperFile, dataMap);
	}

	/**
	 * 生成Service接口类 com.unitd.base.module.logistics.service;
	 *
	 * @throws Exception
	 */
	private void generateServiceFile() throws Exception {
		final String suffix = "Service.java";
		final String path = javaFilePath + packageName.replace(".", "/") + "/module/" + moduleName + "/service/" + className + suffix;
		final String templateName = "Service.ftl";
		generateFileByTemplate(templateName, path);
	}

	/**
	 * 生成ServiceImpl接口实现类
	 *
	 * @throws Exception
	 */
	private void generateServiceImplFile() throws Exception {
		final String suffix = "ServiceImpl.java";
		final String path = javaFilePath + packageName.replace(".", "/") + "/module/" + moduleName + "/service/impl/" + className + suffix;
		final String templateName = "ServiceImpl.ftl";

		generateFileByTemplate(templateName, path);
	}

	/**
	 * 生成Provider接口类
	 *
	 * @throws Exception
	 */
	private void generateProviderFile() throws Exception {
		final String suffix = "Provider.java";
		final String path = javaFilePath + packageName.replace(".", "/") + "/module/" + moduleName + "/provider/" + className + suffix;
		final String templateName = "Proider.ftl";
		File mapperFile = new File(path);

		generateFileByTemplate(templateName, path);
	}

	/**
	 * 生成ProviderImpl接口实现类
	 *
	 * @throws Exception
	 */
	private void generateProviderImplFile() throws Exception {
		final String suffix = "ProviderImpl.java";
		final String path = javaFilePath + packageName.replace(".", "/") + "/module/" + moduleName + "/provider/impl/" + className + suffix;
		final String templateName = "ProviderImpl.ftl";

		generateFileByTemplate(templateName, path);
	}

	/**
	 * 生成Controller类
	 *
	 * @throws Exception
	 */
	private void generateControllerFile() throws Exception {
		final String suffix = "Controller.java";
		final String path = javaFilePath + packageName.replace(".", "/") + "/module/" + moduleName + "/controller/" + className + suffix;
		final String templateName = "Controller.ftl";

		generateFileByTemplate(templateName, path);
	}

	/**
	 * 根据模板文件生成相应的代码文件
	 *
	 * @param templateName 模板文件名称
	 * @param path         需要生成的目标文件全路径
	 */
	private void generateFileByTemplate(String templateName, String path) throws Exception {
		File mapperFile = new File(path);

		if (!mapperFile.getParentFile().exists()) mapperFile.getParentFile().mkdirs();

		Map<String, Object> dataMap = new HashMap<>();
		generateFileByTemplate(templateName, mapperFile, dataMap);
	}

	/**
	 * 真正根据freemark模板生成代码的地方
	 *
	 * @param templateName 模板文件名称
	 * @param file         需要生成的目标文件全路径
	 * @param dataMap      参数集合
	 * @throws Exception
	 */
	private void generateFileByTemplate(final String templateName, File file, Map<String, Object> dataMap) throws Exception {
		Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
		FileOutputStream fos = new FileOutputStream(file);
		dataMap.put("tableName", tableName);
		dataMap.put("tableDesc", tableDesc);
		dataMap.put("packageName", packageName);
		dataMap.put("moduleName", moduleName);
		dataMap.put("className", className);
		dataMap.put("author", author);
		dataMap.put("date", currDate);
		Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 10240);
		template.process(dataMap, out);
	}
}